package utils

import (
	"crypto/hmac"
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	uuid "github.com/satori/go.uuid"
	"gopkg.in/gomail.v2"
	"hr/config"
	"hr/service"
	"math/rand"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"time"
)

// JsonContent JSON数据结构体
type JsonContent struct {
	Success bool        `json:"success"`
	Data    interface{} `json:"data"`
	Msg     string      `json:"msg"`
}

// JsonEcho 输出json数据
func JsonEcho(success bool, data interface{}, msg string) JsonContent {
	return JsonContent{
		Success: success,
		Data:    data,
		Msg:     msg,
	}
}

func EchoError(c *gin.Context, msg string) {
	c.JSON(200, JsonEcho(false, nil, msg))
}

func EchoAccessError(c *gin.Context, msg string) {
	c.JSON(401, JsonEcho(false, nil, msg))
}

func EchoSuccess(c *gin.Context, data interface{}, msg string) {
	c.JSON(200, JsonEcho(true, data, msg))
}

func Hmac(key string, data string) string {
	hmacHash := hmac.New(md5.New, []byte(key))
	hmacHash.Write([]byte(data))
	return hex.EncodeToString(hmacHash.Sum([]byte("")))
}

func Md5V(str string) string {
	h := md5.New()
	h.Write([]byte(str))
	return hex.EncodeToString(h.Sum(nil))
}

func PrintCallErr(functionName string, callName string, err error) {
	fmt.Println(functionName, callName+"返回失败", err)
}

func PrintErr(functionName string, msg ...interface{}) {
	fmt.Println(functionName, msg)
}

func IsStringEmpty(str string) bool {
	return strings.Trim(str, " ") == ""
}

func GetUUID() string {
	u := uuid.NewV4()
	return strings.ReplaceAll(u.String(), "-", "")
}

//Struct转map
func Struct2Map(obj interface{}) map[string]interface{} {
	t := reflect.TypeOf(obj)
	v := reflect.ValueOf(obj)

	var data = make(map[string]interface{})
	for i := 0; i < t.NumField(); i++ {
		data[t.Field(i).Name] = v.Field(i).Interface()
	}
	return data
}

//保存结构体缓存
func SaveCacheJson(filekey string, data interface{}, time time.Duration) error {
	//转换
	result, err := json.Marshal(data)
	if err != nil {
		return err
	}

	return service.FileCache.Save(filekey, string(result), time)
}

//读取结构体缓存
func LoadCacheJson(filekey string) (string, error) {
	result, err := service.FileCache.Fetch(filekey)
	if err != nil {
		return "", err
	}
	return result, nil
}

func CurrentDateTime() string {
	timeUnix := time.Now().Unix()
	formatTimeStr := time.Unix(timeUnix, 0).Format("2006-01-02 15:04:05")
	return formatTimeStr
}

func SendEmail(c *gin.Context, email, name string) (string, error) {
	rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
	code := fmt.Sprintf("%06v", rnd.Int31n(1000000))
	mailConn := map[string]string{
		"user": config.AppConfig.Mail.User,
		"pass": config.AppConfig.Mail.Password,
		"host": config.AppConfig.Mail.Host,
		"port": config.AppConfig.Mail.Port,
	}
	html := fmt.Sprintf(`
		<div>
		<div>
			尊敬的%s，您好！
		</div>
		<div style="margin-top:30px">
			<p>您于 %s 提交的邮箱验证，本次验证码为:</p>
		</div>
		<div style="font-size: 30px;width: 100vw;text-align: center;margin-top: 50px;background: #f0f1f5;font-weight: bolder;height: 100px;line-height: 100px">
			<p><span style="font-size: 30px;text-align: center;font-weight: bolder;">%s</span></p>
		</div>
		<div>
			<p>为了保证账号安全，验证码有效期为5分钟。请确认为本人操作，切勿向他人泄露，感谢您的理解与使用。</p>
		</div>
		<div style="margin-top:30px">
			<p>此邮箱为系统邮箱，请勿回复。</p>
			<p style="text-align: right;">%s</p>
		</div>	
	</div>`, name, CurrentDateTime(), code, config.AppConfig.App.Description)

	m := gomail.NewMessage()
	port, _ := strconv.Atoi(mailConn["port"])
	m.SetAddressHeader("From", mailConn["user"], config.AppConfig.App.Name)
	m.SetHeader("To", email)
	m.SetHeader("Subject", fmt.Sprintf("[%s官方验证码]邮箱验证", config.AppConfig.App.Description))
	m.SetBody("text/html", html)

	d := gomail.NewDialer(mailConn["host"], port, mailConn["user"], mailConn["pass"])
	if err := d.DialAndSend(m); err != nil {
		return "", errors.New("发送验证码失败，请稍后重试")
	}
	return code, nil
}

//获取月份的第一天和最后一天
func GetMonthStartAndEnd(dateStr string) map[string]string {
	dateStrList := strings.Split(dateStr, "-")
	myYear := dateStrList[0]
	myMonth := dateStrList[1]
	// 数字月份必须前置补零
	if len(myMonth) == 1 {
		myMonth = "0" + myMonth
	}
	yInt, _ := strconv.Atoi(myYear)

	timeLayout := "2006-01-02 15:04:05"
	loc, _ := time.LoadLocation("Local")
	theTime, _ := time.ParseInLocation(timeLayout, myYear+"-"+myMonth+"-01 00:00:00", loc)
	newMonth := theTime.Month()

	t1 := time.Date(yInt, newMonth, 1, 0, 0, 0, 0, time.Local).Format("2006-01-02 00:00:00")
	t2 := time.Date(yInt, newMonth+1, 0, 0, 0, 0, 0, time.Local).Format("2006-01-02 00:00:00")
	result := map[string]string{"start": t1, "end": t2}
	return result
}

func IsNum(str string) bool {
	pattern := "\\d+"
	result, _ := regexp.MatchString(pattern, str)
	return result
}

func Get7days() []interface{} {
	days := make([]interface{}, 0)
	currentDate := time.Now()
	for i := 1; i <= 7; i++ {
		days = append(days, currentDate.AddDate(0, 0, -i).Format("2006-01-02"))
	}
	return days
}

func Includes(target string, strArray []string) bool {
	for _, element := range strArray {
		if target == element {
			return true
		}
	}
	return false
}

func TimeIntervalDay(t1, t2 time.Time) int {
	t1 = time.Date(t1.Year(), t1.Month(), t1.Day(), 0, 0, 0, 0, time.Local)
	t2 = time.Date(t2.Year(), t2.Month(), t2.Day(), 0, 0, 0, 0, time.Local)

	return int(t1.Sub(t2).Hours() / 24)
}